#include "canbusiothread.h"
#include "ControlCAN.h"
#include <QTime>
#include <QCoreApplication>
#include <QMetaType>
#include <string.h>
#include <QException>
#include <QDebug>


VCI_BOARD_INFO vbi;

CanBusIoThread::CanBusIoThread()
{

    qRegisterMetaType<VCI_CAN_OBJ>("VCI_CAN_OBJ");
    qRegisterMetaType<DWORD>("DWORD");

    timer_ = new QTimer();
    canOpen = false;
    paused =false;
    stopped = false;

    //一个定时器算帧率
    connect(timer_, SIGNAL(timeout()), this, SLOT(slotCalcFreq()));

}

bool CanBusIoThread::isOpen()
{
   return canOpen;
}

bool CanBusIoThread::OpenCAN(uint deviceType,uint deviceIndex, uint deviceCom ,uint baudrate )
{
         mDeviceType = deviceType; /* USBCAN-2A或USBCAN-2C或CANalyst-II */
         mDeviceIndex = deviceIndex; /* 第1个设备 */
         mCanChanIndex = deviceCom; /* 第1个通道 */
         mBaudRate = baudrate;

         DWORD dwRel;
         dwRel = VCI_OpenDevice(mDeviceType, mDeviceIndex, mCanChanIndex);
         if(dwRel != 1)
         {
            qDebug("open fail");
            return false;
         }
         else
         {
             qDebug("open success");
         }

        dwRel = VCI_ClearBuffer(mDeviceType, mDeviceIndex,mCanChanIndex);

        VCI_INIT_CONFIG vic;
        vic.AccCode=0x80000008;
        vic.AccMask=0xFFFFFFFF;
        vic.Filter=1;
        vic.Mode=0;

        switch (mBaudRate) {
        case 10:
            vic.Timing0=0x31;
            vic.Timing1=0x1c;
            break;
        case 20:
            vic.Timing0=0x18;
            vic.Timing1=0x1c;
            break;
        case 40:
            vic.Timing0=0x87;
            vic.Timing1=0xff;
            break;
        case 50:
            vic.Timing0=0x09;
            vic.Timing1=0x1c;
            break;
        case 80:
            vic.Timing0=0x83;
            vic.Timing1=0xff;
            break;
        case 100:
            vic.Timing0=0x04;
            vic.Timing1=0x1c;
            break;
        case 125:
            vic.Timing0=0x03;
            vic.Timing1=0x1c;
            break;
        case 200:
            vic.Timing0=0x81;
            vic.Timing1=0xfa;
            break;
        case 250:
            vic.Timing0=0x01;
            vic.Timing1=0x1c;
            break;
        case 400:
            vic.Timing0=0x80;
            vic.Timing1=0xfa;
            break;
        case 500:
            vic.Timing0=0x00;
            vic.Timing1=0x1c;
            break;
        case 666:
            vic.Timing0=0x80;
            vic.Timing1=0xb6;
            break;
        case 800:
            vic.Timing0=0x00;
            vic.Timing1=0x16;
            break;
        case 1000:
            vic.Timing0=0x00;
            vic.Timing1=0x14;
            break;
        case 33:
            vic.Timing0=0x09;
            vic.Timing1=0x6f;
            break;
        case 66:
            vic.Timing0=0x04;
            vic.Timing1=0x6f;
            break;
        case 83:
            vic.Timing0=0x03;
            vic.Timing1=0x6f;
            break;
        default:
            break;
        }
        dwRel = VCI_InitCAN(mDeviceType, mDeviceIndex,mCanChanIndex, &vic);
        if(dwRel !=1)
        {
            qDebug("init CAN1 fail:");
            return false;
        }
        else
            qDebug("init CAN1 success:");

        if(VCI_StartCAN(mDeviceType, mDeviceIndex,mCanChanIndex ) !=1)
        {
            return false;
        }
        else
             qDebug("start CAN1 success:");


        canOpen = true;

        //计算帧率
        timer_->start(1000);
        numFrame_ = 0;

        return true;
}

bool CanBusIoThread::CloseCAN()
{
    VCI_CloseDevice(mDeviceType, mDeviceIndex);

    canOpen = false;

	return true;
}

bool CanBusIoThread::InitCAN()
{
	return true;
}

bool CanBusIoThread::sendCanData(int ID, QByteArray cmdBytes)
{
    int count = cmdBytes.count();
    int temp1 = count /8;
    int temp2 = count %8;
    if(temp2>0)
        count = temp1+1;
    else
        count = temp1;

    DWORD dwRel;
    VCI_CAN_OBJ vco[5];
    int i=0;
    for(;i<temp1;i++)
    {
        vco[i].ID =0x00 ;
        vco[i].RemoteFlag = 0;
        vco[i].ExternFlag = 0;
        vco[i].DataLen = 8;
        for(int j = 0;j<8;j++)
            vco[i].Data[j] = cmdBytes[j+(i*8)];
    }

    if(temp2>0)
    {
        vco[i].ID = ID;
        vco[i].RemoteFlag = 0;
        vco[i].ExternFlag = 0;
        vco[i].DataLen = temp2;
        for(int j = 0;j<temp2;j++)
            vco[i].Data[j] = cmdBytes[j+(i*8)];
    }

    dwRel = VCI_Transmit(mDeviceType, mDeviceIndex,mCanChanIndex, vco, count);
    //dwRel = VCI_Transmit(this->mDeviceType, this->mDeviceIndex,this->mCanChanIndex, vco, count);
    if(dwRel>0)
    {
         emit signalSerialCmdSend(cmdBytes);
         return true;
    }

    else
    {
         qDebug("发送错误");
         return false;
    }

}

bool CanBusIoThread::read_ack(QByteArray ack,QByteArray& targetFrame)
{
    QByteArray ba_read;
    bool status;
    int cnt = 0;
    VCI_CAN_OBJ vcoArr[2500];

    qDebug() << "ack" << ack.toHex();

    while(1)
    {

        ulong dwRel = VCI_Receive(mDeviceType, mDeviceIndex,mCanChanIndex, vcoArr, 2500 , 0);
        if(dwRel > 0)
        {
            for(int i =0;i< dwRel;i++)
            {
                QByteArray temp((const char*)(vcoArr[i].Data),8);
                if(temp.indexOf(ack)>=0)
                {
                    //接收帧里面有需要回复的帧
                     emit signalDataRcv(temp);
                     targetFrame = temp;
                     return true;

                }

            }

            cnt++;

		}
		else
		{
			cnt++;
		}

		if (cnt == 5)
		{
			return false;
		}

		sleep(1);

    }


    return status;
}


unsigned char CanBusIoThread::calc_checksum(QByteArray &cmd)
{
    unsigned int length = cmd.length();
    unsigned int sum = 0;

    for(unsigned int index = 0; index < length - 1; index++)
    {
        sum += cmd.at(index);
    }
    return (sum & 0xFF);
}

bool CanBusIoThread::canSetFrameFreq(uint frameFreq)
{
    QByteArray cmd;
    cmd.resize(6);
    cmd[0] = 0x5A;
    cmd[1] = 0x06;
    cmd[2] = 0x03;
    cmd[3] = frameFreq & 0xFF;
    cmd[4] = (frameFreq >> 8) & 0xFF;
    cmd[5] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canOutputSwitch(bool isSwitchOn)
{

    QByteArray cmd;
    cmd.resize(5);
    cmd[0] = 0x5A;
    cmd[1] = 0x05;
    cmd[2] = 0x07;
    cmd[3] = isSwitchOn?0x01:0x00;
    cmd[4] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canOuputFrameFormat(uint format)
{

    QByteArray cmd;
    cmd.resize(5);
    cmd[0] = 0x5A;
    cmd[1] = 5;
    cmd[2] = 0x05;
    cmd[3] = format;
    cmd[4] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

QString CanBusIoThread::canGetVersion(bool& result)
{
    QByteArray cmd;
    QString version ;
    cmd.resize(4);
    cmd[0] = 0x5A;
    cmd[1] = 0x04;
    cmd[2] = 0x01;
    cmd[3] = calc_checksum(cmd);

    QByteArray ack_head;
    ack_head.resize(3);
    ack_head[0] = 0x5A;
    ack_head[1] = 0x07;
    ack_head[2] = 0x01;

    paused = true;

    int tryCnt =0;

    while(1)
    {
        sendCanData(0x03,cmd);
        sleep(100);

        QByteArray targetFrame;
        if(read_ack(ack_head,targetFrame))
        {
            uint8_t v1 = (uint8_t)targetFrame.at(3);
            uint8_t v2 = (uint8_t)targetFrame.at(4);
            uint8_t v3 = (uint8_t)targetFrame.at(5);

            version = QString("V%1.%2.%3") .arg(v1).arg(v2).arg(v3);

            result = true;
            paused=false;
            return version;


        }
		else
		{
			result = false;
			paused = false;
			return "";
		}

    }

     result = false;

     paused=false;

}

bool CanBusIoThread::canSaveConfig()
{
    QByteArray cmd;
    cmd.resize(4);
    cmd[0] = 0x5A;
    cmd[1] = 4;
    cmd[2] = 0x11;
    cmd[3] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);
}

bool CanBusIoThread::canSystemReset()
{
    QByteArray cmd;
    cmd.resize(4);
    cmd[0] = 0x5A;
    cmd[1] = 0x04;
    cmd[2] = 0x02;
    cmd[3] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canFactoryReset()
{

    QByteArray cmd;
    cmd.resize(4);
    cmd[0] = 0x5A;
    cmd[1] = 4;
    cmd[2] = 0x10;
    cmd[3] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canBaudrate(uint baudrate)
{
    QByteArray cmd;

    baudrate = baudrate * 1000;

    cmd.resize(8);
    cmd[0] = 0x5A;
    cmd[1] = 0x08;
    cmd[2] = 0x52;
    cmd[3] = (unsigned char)(baudrate & 0xFF);
    cmd[4] = (unsigned char)(baudrate << 8 & 0xFF);
    cmd[5] = (unsigned char)(baudrate << 16 & 0xFF);
    cmd[6] = (unsigned char)(baudrate << 24 & 0xFF);
    cmd[7] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canSetTxID(uint txID)
{

    QByteArray cmd;
    cmd.resize(8);
    cmd[0] = 0x5A;
    cmd[1] = 0x08;
    cmd[2] = 0x50;
    cmd[3] = (unsigned char)(txID & 0xFF);
    cmd[4] = (unsigned char)(txID << 8 & 0xFF);
    cmd[5] = (unsigned char)(txID << 16 & 0xFF);
    cmd[6] = (unsigned char)(txID << 24 & 0xFF);
    cmd[7] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);
}

bool CanBusIoThread::canSetRxID(uint rxID)
{

    QByteArray cmd;
    cmd.resize(8);
    cmd[0] = 0x5A;
    cmd[1] = 0x08;
    cmd[2] = 0x51;
    cmd[3] = (unsigned char)(rxID & 0xFF);
    cmd[4] = (unsigned char)(rxID << 8 & 0xFF);
    cmd[5] = (unsigned char)(rxID << 16 & 0xFF);
    cmd[6] = (unsigned char)(rxID << 24 & 0xFF);
    cmd[7] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);
}

bool CanBusIoThread::canSetFrameType(uint frameType)
{

    QByteArray cmd;
    cmd.resize(5);
    cmd[0] = 0x5A;
    cmd[1] = 0x05;
    cmd[2] = 0x5D;
    cmd[3] = frameType;
    cmd[4] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);

}

bool CanBusIoThread::canSetParam(uint frameType, uint baudrate, ulong rxID, ulong txID)
{

    QByteArray cmd;
    cmd.resize(14);

    cmd[0] = 0x5A;
    cmd[1] = 0x0E;
    cmd[2] = 0x51;
    cmd[3] = frameType;


    int baudrateByte = 0;
    switch (baudrate) {

      case 1000:
          baudrateByte = 0;
          break;
      case 900:
          baudrateByte = 1;
          break;
      case 800:
          baudrateByte = 2;
          break;
      case 666:
          baudrateByte = 3;
          break;
      case 600:
          baudrateByte = 4;
          break;
      case 500:
          baudrateByte = 5;
          break;
      case 400:
          baudrateByte = 6;
          break;
      case 300:
          baudrateByte = 7;
          break;
      case 250:
          baudrateByte = 8;
          break;
      case 225:
          baudrateByte = 9;
          break;
      case 200:
          baudrateByte = 10;
          break;
      case 160:
          baudrateByte = 11;
          break;
      case 150:
          baudrateByte = 12;
          break;
      case 144:
          baudrateByte = 13;
         break;
      case 125:
          baudrateByte = 14;
          break;
      case 120:
          baudrateByte = 15;
          break;
      case 100:
          baudrateByte = 16;
          break;


    }

    cmd[4] = baudrateByte;

    cmd[5] = (unsigned char)(rxID & 0xFF);
    cmd[6] = (unsigned char)(rxID << 8 & 0xFF);
    cmd[7] = (unsigned char)(rxID << 16 & 0xFF);
    cmd[8] = (unsigned char)(rxID << 24 & 0xFF);

    cmd[9] = (unsigned char)(txID & 0xFF);
    cmd[10] = (unsigned char)(txID << 8 & 0xFF);
    cmd[11] = (unsigned char)(txID << 16 & 0xFF);
    cmd[12] = (unsigned char)(txID << 24 & 0xFF);

    cmd[13] = calc_checksum(cmd);

    return  sendCanData(0x03,cmd);


}

void CanBusIoThread::run()
{
    while(!stopped)
    {
        if(paused)
        {
            sleep(1000);
            continue;
        }
        DWORD dwRel;
        VCI_CAN_OBJ vcoArr[2500];
        try {

            dwRel = VCI_Receive(mDeviceType, mDeviceIndex,mCanChanIndex, vcoArr, 2500 , 0);
            if(dwRel > 0)
            {
                for(int i =0;i< dwRel;i++)
                {
                    VCI_CAN_OBJ vcoItem = vcoArr[i];
                    uint dist = (vcoItem.Data[1] << 8) | (vcoItem.Data[0] & 0xff);
                    uint amp = (vcoItem.Data[3] << 8) | (vcoItem.Data[2] & 0xff);
                    passDist_.push_back(dist);
                    passAmp_.push_back(amp);

                    QByteArray rxFrame ;

                    for (int i = 0; i< 8;i++) {
                          rxFrame[i] = vcoItem.Data[i];
                    }
                    passRxFrame_.push_back(rxFrame.toHex(' '));
                    numFrame_++;
                }

                emit signalDistance(passDist_,passAmp_,passRxFrame_,freq_);

                passDist_.clear();
                passAmp_.clear();
                passRxFrame_.clear();
            }
            else
            {
                qDebug("No Data Received!");
				sleep(1000);
            }

        } catch (QException e) {

            qErrnoWarning(e.what());
        }


        sleep(1);
    }
    stopped = false;
}

void CanBusIoThread::sleep(unsigned int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void CanBusIoThread::slotCalcFreq()
{
    freq_ = numFrame_;
    numFrame_ = 0;
}
